package clustering

import collection.JavaConversions
import collection.JavaConversions._

import de.lmu.ifi.dbs.elki.result.ClusterOrderResult
import de.lmu.ifi.dbs.elki.distance.DoubleDistance
import de.lmu.ifi.dbs.elki.algorithm.clustering.DeLiClu
import de.lmu.ifi.dbs.elki.database.{Associations, SpatialIndexDatabase}
import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.deliclu.{DeLiCluEntry, DeLiCluNode, DeLiCluTree}
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.ListParameterization
import javax.imageio.ImageIO
import java.io.File
import util.Random
import java.awt.Color
import de.lmu.ifi.dbs.elki.data.DoubleVector
import de.lmu.ifi.dbs.elki.utilities.pairs.Pair
import de.lmu.ifi.dbs.elki.database.AssociationID
import collection.mutable.ArrayBuffer


/**
 * Created by IntelliJ IDEA.
 * User: denny
 * Date: Jul 26, 2010
 * Time: 1:09:50 PM
 * To change this template use File | Settings | File Templates.
 */

object ElkiTestImgColors extends Application{
  val parm = new ListParameterization(JavaConversions.asCollection(List()))
  //parm.addParameter(FileBasedDatabaseConnection.INPUT_ID, new File("/opt/elki/exampledata.txt"))

//  val fileParm =  new FileParameter(FileBasedDatabaseConnection.INPUT_ID, FileParameter.FileType.INPUT_FILE )
//  fileParm.setValue(new File("/opt/elki/exampledata.txt"))
//  parm.setValueForOption(fileParm)

//  class MySeqDB extends SequentialDatabase{
//    override def insert(objectsAndAssociationsList: java.util.List[Pair[Nothing, Associations]]) = {
//      super.insert(objectsAndAssociationsList)
//    }
//
//  }
//
//  parm.addParameter(AbstractDatabaseConnection.DATABASE_ID, classOf[MySeqDB])
//  val dbc = new FileBasedDatabaseConnection(parm)
//
//  val db = dbc.getDatabase(new DummyNormalization)
//  println("db size %d".format( db.size ))

  //val dbseq = new SequentialDatabase[DoubleVector]

//  parm.addParameter(SpatialIndexDatabase.INDEX_ID, classOf[DeLiCluTree[DoubleVector]])
//  val dbseq = new SpatialIndexDatabase[DoubleVector,DeLiCluNode,DeLiCluEntry](parm)
//  //dbseq.insert()
//  for( i <- 1 to 10 ){
//    val vec = new DoubleVector(Array(10.0,i))
//    dbseq.insert(new Pair(vec, new Associations()))
//  }
//  for( i <- 50 to 8000 ){
//    val vec = new DoubleVector(Array(10.0,i))
//    dbseq.insert(new Pair(vec, new Associations()))
//  }

  val (dbseq,points) = sampleColorsDB()
  println("dbseq size %d".format( dbseq.size ))

  //parm.addParameter(DBSCAN.MINPTS_ID, new java.lang.Integer(3))

//  parm.addParameter(DBSCAN.EPSILON_ID, new java.lang.Double(5))
//  val alg = new DBSCAN[DoubleVector,DoubleDistance](parm) //  [DoubleVector, DoubleDistance](parm)
//  val cl :Clustering[Model] = alg.run(dbseq)
//  println("clusters count %d".format( cl.getAllClusters.size ))
//  for( cli <- cl.getAllClusters ){
//    val ch = cli.getChildren
//    val ids = cli.getIDs
//    println("ch=%s, ids=%s, vals=%s".format(ch,ids, ids.map(i => dbseq.get(i)) ))
//  }

  parm.addParameter(DeLiClu.MINPTS_ID, new java.lang.Integer(3))
  val alg = new DeLiClu[DoubleVector,DoubleDistance](parm)
  val res : ClusterOrderResult[DoubleDistance] = alg.run(dbseq)

  val clustOrder = res.getClusterOrder.toList.toArray
  val reachArray = clustOrder.map( _.getReachability.getValue.doubleValue ).toArray

  def clustEnd(idx:Int)={
    var stop=false
    var i = idx+1
    while( !stop && i<reachArray.size ){
      if( reachArray(i)>=0.95*reachArray(idx) ){
        stop=true
      }
      i += 1
    }
    i
  }

  def writeCluster(start:Int, end:Int){
    val img = ImageIO.read(new File("/opt/tmp/face.jpg"))
    val g = img.getGraphics
    g.setColor(Color.BLUE)
    for( i <- start+1 to end-1 ){
      val idx = dbseq.getAssociation[java.lang.Integer](AssociationID.ROW_ID, clustOrder(i).getID).intValue
//      val dv : DoubleVector = dbseq.get( clustOrder(i).getID )
//      val x = dv.getValues()(0).toInt
//      val y = dv.getValues()(1).toInt
      val x = points(idx)._1
      val y = points(idx)._2
      g.drawOval(x-2, y-2, 5,5)
    }
    ImageIO.write(img, "jpg", new File("/opt/tmp/clust/faceClust%d-%d.jpg".format(start,end)))
  }

  for( i <- 0 until reachArray.size ){
    //println("%s reachability %s".format( dbseq.get(orde.getID), orde.getReachability ))
    //val r:Double = orde.getReachability.getValue.doubleValue*2
    var r = reachArray(i)
    val iend = clustEnd((i))
    var st=""
    if( iend>i+20 ){
      writeCluster(i, iend)
      st = "#"
    }
    //val st = if( clustStart(i, 20 ) ) "#" else ""
    println("%3d %s %s".format( r.toInt , "="*(r.toInt min 200), st ))
  }


//  val d:Database = new SequentialDatabase[DoubleVector]
//  d.
//  alg.run()

  def sampleColorsDB()={
    val parm = new ListParameterization(JavaConversions.asCollection(List()))
    val img = ImageIO.read(new File("/opt/tmp/face.jpg"))
    val (w,h) = (img.getWidth, img.getHeight)
    val rnd = new Random
    parm.addParameter(SpatialIndexDatabase.INDEX_ID, classOf[DeLiCluTree[DoubleVector]])
    val dbseq = new SpatialIndexDatabase[DoubleVector,DeLiCluNode,DeLiCluEntry](parm)

    val points = new ArrayBuffer[(Int,Int)]
    for( i <- 1 to 2000 ){
      val x = rnd.nextInt(w)
      val y = rnd.nextInt(h)
      points += ((x,y))
      val c = new Color(img.getRGB(x,y))
      val vec = new DoubleVector(Array(/*x, y,*/ c.getRed.toDouble, c.getGreen, c.getBlue))
      val assoc = new Associations
      assoc.put[java.lang.Integer](AssociationID.ROW_ID, i-1)
      val p = new Pair(vec, assoc)

//      error: overloaded method value insert with alternatives:
//(java.util.List[de.lmu.ifi.dbs.elki.utilities.pairs.Pair[de.lmu.ifi.dbs.elki.data.DoubleVector,de.lmu.ifi.dbs.elki.database.Associations]])Unit <and>
//(de.lmu.ifi.dbs.elki.utilities.pairs.Pair[de.lmu.ifi.dbs.elki.data.DoubleVector,de.lmu.ifi.dbs.elki.database.Associations])java.lang.Integer
//cannot be applied to ((de.lmu.ifi.dbs.elki.data.DoubleVector, de.lmu.ifi.dbs.elki.database.Associations))
//dbseq.insert(p)

      dbseq.insert(p)
    }
    (dbseq, points.toArray)
  }
}